package com.it.tydic.estate.common.security;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.web.cors.CorsUtils;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启security注解
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private LoginSuccessHandler successHandler;

	@Autowired
	private LoginFailureHandler failureHandler;

	@Autowired
	private LoginOutHandler  logoutHandler;

	@Autowired
	private MyInvocationSecurityMetadataSource metadataSource;

	@Autowired
	private MyAccessDecisionManager myAccessDecisionManager;

	@Autowired
	private MyAccessDeniedHandler accessDeniedHandler;

	@Bean
	PasswordEncoder passwordEncoder() {
		return PasswordEncoderFactories.createDelegatingPasswordEncoder();
	}


	/**
	 * 注入AuthenticationManager接口，启用OAuth2密码模式
	 *
	 * @return
	 * @throws Exception
	 */
	@Bean
	@Override
	public AuthenticationManager authenticationManagerBean() throws Exception {
		AuthenticationManager manager = super.authenticationManagerBean();
		return manager;
	}

	@Override
	public void configure(WebSecurity web) throws Exception {
		// 忽略登录界面
		web.ignoring().antMatchers("/estate/login");
		web.ignoring(). antMatchers("/estate/swagger-ui.html")
				.antMatchers("/estate/webjars/**")
				.antMatchers("/estate/v2/**")
				.antMatchers("/estate/swagger-resources/**")
				.antMatchers("/estate/oauth/**")
				.antMatchers("/oauth/check/**");

	}

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry
				= http.authorizeRequests();
		registry.requestMatchers(CorsUtils::isPreFlightRequest).permitAll();//让Spring security放行所有preflight reques

		http
				.authorizeRequests()
				//处理跨域请求中的Preflight请求
				.withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
					@Override
					public <O extends FilterSecurityInterceptor> O postProcess(O object) {
						object.setSecurityMetadataSource(metadataSource);
						object.setAccessDecisionManager(myAccessDecisionManager);
						return object;
					}
				})
				.and()
				.requestMatchers().anyRequest()
				.and()
				.authorizeRequests()
				.antMatchers("/oauth/**").permitAll()
				.antMatchers("/estate/oauth/**").permitAll()
				.and()
				.formLogin()
				.loginProcessingUrl("/login")
				.successHandler(successHandler) /* 设置成功处理器 */
				.failureHandler(failureHandler).permitAll().and()
				.logout().clearAuthentication(true).
				invalidateHttpSession(true).
				addLogoutHandler(logoutHandler).permitAll().
				and().csrf().disable().
				exceptionHandling().accessDeniedHandler(accessDeniedHandler)
				.and().cors().
				and().sessionManagement().maximumSessions(9);

	}
}
